package simulaco.business;

import gminet.infra.business.BusinessException;
import gminet.infra.business.BusinessObject;
import gminet.infra.db.Transaction;
import gminet.infra.db.TransactionException;
import gminet.infra.toolkit.DateToolkit;
import gminet.infra.toolkit.NumberToolkit;
import gminet.infra.toolkit.StringToolkit;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import simulaco.dao.ConcursoDAO;
import simulaco.dao.ConcursoFilter;
import simulaco.dao.InstituicaoDAO;
import simulaco.dao.InstituicaoFilter;
import simulaco.dto.Instituicao;
import simulaco.dto.Situacao;

public class InstituicaoBusiness extends BusinessObject {

    private static List<Instituicao> CACHE_LIST_INSTITUICOES = null;
    private static List<Instituicao> CACHE_LIST_INSTITUICOES_ACTIVES = null;

    public static Instituicao findByPK(int instituicaoId) throws TransactionException {

        Instituicao instituicao = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            instituicao = InstituicaoDAO.findByPK(instituicaoId, conn);
        } finally {
            transaction.release();
        }
        return instituicao;
    }

    public static List<Instituicao> findAll() throws TransactionException {

        if (CACHE_LIST_INSTITUICOES == null || CACHE_LIST_INSTITUICOES.size() == 0) {
            List<Instituicao> instituicoes = null;
            Transaction transaction = createTransaction();
            try {
                Connection conn = transaction.getConnection();
                instituicoes = InstituicaoDAO.findAll(conn);
            } catch (TransactionException te) {
                transaction.rollback();
                throw te;
            } finally {
                transaction.release();
            }
            // CACHE
            if (CACHE_LIST_INSTITUICOES == null) {
                CACHE_LIST_INSTITUICOES = new ArrayList<Instituicao>();
            }
            CACHE_LIST_INSTITUICOES.addAll(instituicoes);
        }
        return CACHE_LIST_INSTITUICOES;
    }

    public static List<Instituicao> findActives() throws TransactionException {

        if (CACHE_LIST_INSTITUICOES_ACTIVES == null || CACHE_LIST_INSTITUICOES_ACTIVES.size() == 0) {
            List<Instituicao> instituicoes = null;
            Transaction transaction = createTransaction();
            try {
                Connection conn = transaction.getConnection();
                InstituicaoFilter filter = new InstituicaoFilter();
                filter.setCodigoSituacao(Situacao.HABILITADO.getCodigo());
                instituicoes = InstituicaoDAO.findByFilter(filter, conn);
            } catch (TransactionException te) {
                transaction.rollback();
                throw te;
            } finally {
                transaction.release();
            }
            // CACHE
            if (CACHE_LIST_INSTITUICOES_ACTIVES == null) {
                CACHE_LIST_INSTITUICOES_ACTIVES = new ArrayList<Instituicao>();
            }
            CACHE_LIST_INSTITUICOES_ACTIVES.addAll(instituicoes);
        }
        return CACHE_LIST_INSTITUICOES_ACTIVES;
    }

    public static Instituicao insert(Instituicao instituicao) throws BusinessException, TransactionException {

        Instituicao newInstituicao = null;
        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // INSTITUICAO
            Date dataAtual = DateToolkit.getDate();
            int rangeId = createRangeId(instituicao.getNome());
            instituicao.setCodigo(InstituicaoDAO.getNextCodigo(conn, rangeId, rangeId + 1000));
            if (instituicao.getSituacao().getCodigo() == 0) {
                instituicao.setSituacao(Situacao.DESABILITADO);
            }
            instituicao.setDataCadastro(dataAtual);
            InstituicaoDAO.insert(instituicao, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
            //
            newInstituicao = instituicao;
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
        return newInstituicao;
    }

    private static int createRangeId(String instituicaoName) {

        String strCodigo = "1";
        String caracter1 = instituicaoName.substring(0, 1).toUpperCase();
        String caracter2 = instituicaoName.length() > 1 ? instituicaoName.substring(1, 2).toUpperCase() : "A";
        int valor1 = Math.abs(caracter1.compareTo("A") + 1);
        if (StringToolkit.isDigit(caracter1)) {
            valor1 = 0;
        }
        int valor2 = Math.abs(caracter2.compareTo("A") / 3);
        if (StringToolkit.isDigit(caracter2)) {
            valor2 = 0;
        }
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor1, 99), 2);
        strCodigo += NumberToolkit.getStringFromInt(Math.min(valor2, 9), 1);
        strCodigo += "000";
        return Integer.parseInt(strCodigo);
    }

    public static void update(Instituicao instituicao) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            InstituicaoDAO.update(instituicao, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void updateStatus(Instituicao instituicao) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            Instituicao auxInstituicao = InstituicaoDAO.findByPK(instituicao.getCodigo(), conn);
            auxInstituicao.setSituacao(instituicao.getSituacao());
            InstituicaoDAO.update(auxInstituicao, conn);
            // COMMIT
            transaction.commit();
            // RELEASE CACHE
            releaseCache();
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    public static void delete(Instituicao instituicao) throws BusinessException, TransactionException {

        Transaction transaction = createTransaction();
        try {
            Connection conn = transaction.getConnection();
            // VERIFICA SE TEM CONCURSO VINCULADOS
            ConcursoFilter filter = new ConcursoFilter();
            filter.setCodigoInstituicao(instituicao.getCodigo());
            if (ConcursoDAO.findByFilter(filter, conn).size() > 0) {
                throw new BusinessException("Não é possivel excluir esta instituição. Existem concursos vinculados.");
            } else {
                // EXCLUI A INSTITUICAO
                InstituicaoDAO.delete(instituicao, conn);
                transaction.commit();
                // RELEASE CACHE
                releaseCache();
            }
        } catch (TransactionException te) {
            transaction.rollback();
            throw te;
        } finally {
            transaction.release();
        }
    }

    private static void releaseCache() {

        // CACHE_LIST_INSTITUICOES
        if (CACHE_LIST_INSTITUICOES != null) {
            CACHE_LIST_INSTITUICOES.clear();
        }
        CACHE_LIST_INSTITUICOES = null;
        // CACHE_LIST_INSTITUICOES_ACTIVES
        if (CACHE_LIST_INSTITUICOES_ACTIVES != null) {
            CACHE_LIST_INSTITUICOES_ACTIVES.clear();
        }
        CACHE_LIST_INSTITUICOES_ACTIVES = null;
    }

}
